package com.ease.util {

   import flash.events.Event;
   import flash.events.EventDispatcher;

   import mx.core.FlexGlobals;

   /**
    * Registers an object with the platform whenever a reference is required and unregisters
    * when no references are any longer necessary.
    *
    * To enable the tracking use dispatchUsingTracker and registerResponse methods.
    */
   public class ObjectRegistrationTracker {

      private var _refCount:uint = 0;

      /**
       * Maintaining a weakreference to the object being tracked so that tracking an object
       * does not lead to an extra reference.
       */
      private var _trackedObject:WeakReference;

      /**
       * Constructor.
       *
       * @param trackedObject
       *    Object to be tracked.
       */
      public function ObjectRegistrationTracker( trackedObject:EventDispatcher ):void {
         _trackedObject = new WeakReference( trackedObject );
      }

      /**
       * Method guarantess object registration with the platform before dispatching
       * the supplied event using the dispatcher being tracked.
       *
       * @param event
       *    Event to be dispatched.
       *
       * @param expectResponse
       *    If no response is expected will immediately call the registerResponse method.
       *
       */
      public function dispatchUsingTracked(
         event:Event,
         expectResponse:Boolean = true):void {
         var dispatcher:EventDispatcher = _trackedObject.object as EventDispatcher;
         if (dispatcher == null) {
            return;
         }
         incrementReference( dispatcher );
         dispatcher.dispatchEvent( event );
         if (!expectResponse) {
            registerResponse();
         }
      }

      /**
       * Call this method to register a response which in turn allows for the object to
       * be unregistered from the platform.
       */
      public function registerResponse():void {
         decrementReference( _trackedObject.object );
      }

      /**
       * Call this method before performing an operation that requires registration with
       * the platform.
       */
      private function incrementReference( trackedObject:* ):void {
         if (trackedObject == null) {
            return;
         }
         if (_refCount == 0) {
            FlexGlobals.topLevelApplication.dispatchEvent(
               ObjectEvent.newAddition( trackedObject ));
         }
         _refCount++;
      }

      /**
       * Call this method following an operation that removes the need for object
       * registration with the platform.
       */
      private function decrementReference( trackedObject:* ):void {
         if (trackedObject == null) {
            return;
         }
         _refCount--;
         if (_refCount > 0) {
            return;
         }
         FlexGlobals.topLevelApplication.dispatchEvent(
            ObjectEvent.newRemoval( trackedObject ) );
      }
   }
}